package org.javacore.Utils

import org.joda.time.*

import java.text.SimpleDateFormat

class DateTimeUtils {

	//============================================================
	// Get an DateTime instance
	//============================================================
	static DateTime get(Map map) {
		def fields=[year:1,month:1,day:1,hour:0,minute:0,second:0,millis:0]
		map.each {k,v -> fields[k]=v.toInteger()}
		return new DateTime(fields.year, fields.month, fields.day, fields.hour, fields.minute, fields.second, fields.millis)
	}

	static DateTime getNow() {
		return new DateTime()
	}

	static DateTime get(int year=1, int month=1, int day=1, int hour=0, int minute=0, int second=0, int millis=0) {
		return new DateTime(year, month, day, hour, minute, second, millis)
	}

	static DateTime toDateTime(Map self) {
		return get(self)
	}

	static DateTime toDateTime(Date self) {
		return new DateTime(self)
	}
/*
	static DateTime toDateTimeFromStr(String strDate, String format='yyyy-MM-dd') {
		return new DateTime(Utils.string2Date(strDate,format))
	}*/

	static Date toDate(Map self) {
		return toDateTime(self).toDate()
	}

	//============================================================
	// Period
	//============================================================
	static Years getYears(Integer self) {
		Years.years(self)
	}

	static Months getMonths(Integer self) {
		Months.months(self)
	}

	static Weeks getWeeks(Integer self) {
		Weeks.weeks(self)
	}

	static Days getDays(Integer self) {
		Days.days(self)
	}

	static Hours getHours(Integer self) {
		Hours.hours(self)
	}

	static Minutes getMinutes(Integer self) {
		Minutes.minutes(self)
	}

	static Seconds getSeconds(Integer self) {
		Seconds.seconds(self)
	}

	//============================================================
	// Ago and FromNow
	//============================================================
	static DateTime getAgo(ReadablePeriod self) {
		DateTime now = new DateTime()
		now - self
	}

	static DateTime getLater(ReadablePeriod self) {
		DateTime now = new DateTime()
		now + self
	}

	//============================================================
	// Before and After
	//============================================================
	static DateTime before(ReadablePeriod self, DateTime dateTime) {
		dateTime - self
	}

	static Date before(ReadablePeriod self, Date date) {
		before(self, toDateTime(date)).toDate()
	}

	static DateTime after(ReadablePeriod self, DateTime dateTime) {
		dateTime + self
	}

	static Date after(ReadablePeriod self, Date date) {
		after(self, toDateTime(date)).toDate()
	}

	//============================================================
	// First day and Last day of month
	//============================================================
	static DateTime getFirstDayOfMonth(DateTime self) {
		self.dayOfMonth().withMinimumValue()
	}

	static DateTime getLastDayOfMonth(DateTime self) {
		self.dayOfMonth().withMaximumValue()
	}

	static Date getFirstDayOfMonth(Date self) {
		getFirstDayOfMonth(toDateTime(self)).toDate()
	}

	static Date getLastDayOfMonth(Date self) {
		getLastDayOfMonth(toDateTime(self)).toDate()
	}
/*
    static Date getFirstDayOfMonth(String yearMonthStr) {
        Date date = Utils.yearMonthString2Date(yearMonthStr)
        getFirstDayOfMonth(date)
    }

    static Date getLastDayOfMonth(String yearMonthStr) {
        Date date = Utils.yearMonthString2Date(yearMonthStr)
        getLastDayOfMonth(date)
    }

	static String getFirstDayOfMonthStr(Date self) {
		return Utils.date2DateString(getFirstDayOfMonth(self))
	}

	static String getLastDayOfMonthStr(Date self) {
		return Utils.date2DateString(getLastDayOfMonth(self))
	}*/

	static boolean isLastDayOfMonth(Date self){
	    return isSameDate(self, getLastDayOfMonth(self))
	}

	//============================================================
	// At
	// DateTime dt = new DateTime()
	// dt.at(4:30) will return the same date as dt,
	// while hours of day set to 4, minutes of hour set to 30,
	// seconds and milliseconds set to 0
	//============================================================
	static DateTime at(DateTime self, Map hourMinute) {
		int hour = 0
		int minute = 0
		hourMinute.each{k,v->hour=k.toInteger();minute=v.toInteger()}
		self.withHourOfDay(hour).withMinuteOfHour(minute).withSecondOfMinute(0).withMillisOfSecond(0)
	}

	static Date at(Date self, Map hourMinute) {
		at(toDateTime(self), hourMinute).toDate()
	}

	//============================================================
	// Set Field
	//============================================================
	private static def setFieldMethods = [
	       		year:{dt,v->dt.withYear(v)},
	       		month:{dt,v->dt.withMonthOfYear(v)},
	       		day:{dt,v->dt.withDayOfMonth(v)},
	       		dayOfWeek:{dt,v->dt.withDayOfWeek(v)},
	       		dayOfYear:{dt,v->dt.withDayOfYear(v)},
	       		hour:{dt,v->dt.withHourOfDay(v)},
	       		minute:{dt,v->dt.withMinuteOfHour(v)},
	       		second:{dt,v->dt.withSecondOfMinute(v)},
	       		millis:{dt,v->dt.withMillisOfSecond(v)},
	       		weekOfWeekyear:{dt,v->
	       			dt.withWeekOfWeekyear(v)
	       		}
	       		]

	static DateTime with(DateTime self, Map fields) {
		fields.entrySet().inject(self){dt, entry ->
			setFieldMethods[entry.key].call(dt, entry.value.toInteger())
		}
	}

	static Date with(Date self, Map fields) {
		with(toDateTime(self), fields).toDate()
	}

	static DateTime zeroTime(DateTime self) {
	        with(self, [hour:0, minute:0, second:0, millis:0])
	}

	static Date zeroTime(Date self) {
                zeroTime(toDateTime(self)).toDate()
	}

	//============================================================
	// 计算两个日期之间有多少个星期几
	// start 开始日期
	// end 结束日期
	// dayOfWeek 1 - 7 星期一 ～ 星期天
	//============================================================
	static int getDayOfWeeksBetween(DateTime start, DateTime end, int dayOfWeek) {
	    assert dayOfWeek >= 1 && dayOfWeek <= 7
	    int days = Days.daysBetween(start, end).days
            return (int)((start.minusDays(dayOfWeek).dayOfWeek().get() + days) / 7)
	}

	static int getDayOfWeeksBetween(Date start, Date end, int dayOfWeek) {
	    getDayOfWeeksBetween(new DateTime(start), new DateTime(end), dayOfWeek)
	}

	//============================================================
	// 计算两个日期之间有多少个工作日（周一至周五）
	// start 开始日期
	// end 结束日期
	//============================================================
	static int getWorkingDaysBetween(DateTime start, DateTime end) {
	    [1,2,3,4,5].sum(0){getDayOfWeeksBetween(start, end, it)}
	}

	static int getWorkingDaysBetween(Date start, Date end) {
	    getWorkingDaysBetween(new DateTime(start), new DateTime(end))
	}


	//============================================================
	// 计算两个日期之间有多少个周六（周六）
	// start 开始日期
	// end 结束日期
	//============================================================
	static int getSaturDaysBetween(Date start, Date end) {
	    getSaturDaysBetween(new DateTime(start), new DateTime(end))
	}

	static int getSaturDaysBetween(DateTime start, DateTime end) {
		return getDayOfWeeksBetween(start, end, 6)
	}

	//============================================================
	// 与字符串转换
	//============================================================
	/*static String toDateStr(DateTime self) {
		Utils.date2DateString(self.toDate())
	}

	static String toDateStr(Date self) {
		Utils.date2DateString(self)
	}

	static String toYearMonthStr(DateTime self) {
		Utils.date2YearMonthString(self.toDate())
	}

	static String toYearMonthStr(Date self) {
		Utils.date2YearMonthString(self)
	}*/

    /**
     * 把yyyy-MM-dd, yyyy-MM, yyyy/MM/dd, yyyy/MM, yyyyMM 格式的字符串转成 yyyy-MM 格式
     * 若参数的的格式或月份不正确(如2000-112，2000-13等)则返回null
     */
    /*static String toYearMonthStr(String str) {
        String yearMonth = str?.replace('/','-')
        if(yearMonth ==~ /\d{4}-\d\d?(-\d\d?)?/) {
            yearMonth = yearMonth.find(/\d{4}-\d\d?/)
            if(yearMonth.length() == 6) {
                yearMonth = yearMonth.replace('-','-0')
            }
            def month = yearMonth.substring(5).toInteger()
            if(month <= 12 && month > 0) {
                return yearMonth
            }
        }
        else if(yearMonth ==~ /\d{6}/){
            return Utils.formatYearMonth(yearMonth)
        }
        return null
    }*/

	//判断两个时间段是否有交集
	static boolean isIntersection(DateTime fromTime1, DateTime toTime1, DateTime fromTime2, DateTime toTime2){
		return (fromTime1<=toTime2 && toTime1>=fromTime2)
	}

	static boolean isIntersection(Date fromTime1, Date toTime1, Date fromTime2, Date toTime2){
		return isIntersection(new DateTime(fromTime1),new DateTime(toTime1),new DateTime(fromTime2),new DateTime(toTime2))
	}

	//判断两个时间是否与一天有交集
	static boolean isIntersection(Date date, DateTime fromTime2, DateTime toTime2){
		DateTime fromTime1 = new DateTime(date).toDateMidnight().toDateTime()
		DateTime toTime1 = new DateTime(date).plusDays(1).toDateMidnight().toDateTime()

		return isIntersection(fromTime1,toTime1,fromTime2,toTime2)
	}

	//取得两个时间段的交集Map[fromTime,toTime]
	static Map getIntersection(DateTime fromTime1, DateTime toTime1, DateTime fromTime2, DateTime toTime2){
		def retMap = [:]

		if(isIntersection(fromTime1,toTime1,fromTime2,toTime2)==false){
			return retMap
		}

		if(fromTime1>=fromTime2){
			retMap.fromTime = fromTime1
		}
		else{
			retMap.fromTime = fromTime2
		}

		if(toTime1<=toTime2){
			retMap.toTime = toTime1
		}
		else{
			retMap.toTime = toTime2
		}

		return retMap

	}

	//判断两个日期是否一样
	static boolean isSameDate(DateTime date1, DateTime date2){
		return (date1.year().get()==date2.year().get()
		&& date1.monthOfYear().get()==date2.monthOfYear().get()
		&& date1.dayOfMonth().get()==date2.dayOfMonth().get())
	}

	static boolean isSameDate(Date date1, Date date2){
		return isSameDate(new DateTime(date1),new DateTime(date2))
	}

	//离结束时间还有多少时间
	static String getLeftTimeDesc(DateTime endDate, DateTime dNow=new DateTime()){
		def p=new Period(dNow,endDate)

		String desc = '还有'
		if(p.years>0){
			desc+= p.years+"年"
			}
		if(p.months>0){
			desc+= p.months+"月"
			}
		if(p.days>0){
			desc+= p.days+"日"
			}
		if(p.hours>0){
			desc+= p.hours+"小时"
			}
		if(p.minutes>0){
			desc+= p.minutes+"分"
			}
		if(p.seconds>0){
			desc+= p.seconds+"秒"
			}

		if(desc=='还有'){
			desc = '已结束'
		}

		return desc
	}

	//得到季度
	static int getQuarterNum(DateTime now=DateTimeUtils.getNow()){
		int mon = now.monthOfYear().get()
		if(mon<=3){
			return 1
		}
		else if(mon<=6){
			return 2
		}
		else if(mon<=9){
			return 3
		}
		else {
			return 4
		}
	}

	//得到上季度
	static int getPreQuarterNum(DateTime now=DateTimeUtils.getNow()){
		int preQuarter = getQuarterNum(now)-1
		if(preQuarter==0){
			preQuarter = 4
		}
		return preQuarter
	}

	//得到上季度的年份
	static int getPreQuarterYear(DateTime now=DateTimeUtils.getNow()){
		int year
		if(getPreQuarterNum(now)==4){
			year = now.plusYears(-1).year().get()
		}
		else{
			year = now.year().get()
		}

		return year
	}

	//得到上季度的开始月份
	static int getPreQuarterStartMonth(DateTime now=DateTimeUtils.getNow()){
		return getQuarterStartMonth(getPreQuarterNum(now))
	}

	//得到季度的开始月份
	static int getQuarterStartMonth(DateTime now=DateTimeUtils.getNow()){
		return getQuarterStartMonth(getQuarterNum(now))
	}

	//得到季度的开始月份
	static int getQuarterStartMonth(int quarter){
		return quarter*3-2
	}


	//得到上季度的开始月份
	static int getPreQuarterEndMonth(DateTime now=DateTimeUtils.getNow()){
		return getQuarterEndMonth(getPreQuarterNum(now))
	}

	//得到季度的结束月份
	static int getQuarterEndMonth(DateTime now=DateTimeUtils.getNow()){
		return getQuarterEndMonth(getQuarterNum(now))
	}

	//得到季度的结束月份
	static int getQuarterEndMonth(int quarter){
		return quarter*3
	}

	//得到上一季度的开始日期
	static DateTime getStartDateOfPreQuarter(DateTime now=DateTimeUtils.getNow()){
		DateTime dt = DateTimeUtils.getFirstDayOfMonth(
				DateTimeUtils.get(getPreQuarterYear(now),getPreQuarterStartMonth(now))
			)

		return dt
	}

	//得到上一季度的结束日期
	static DateTime getEndDateOfPreQuarter(DateTime now=DateTimeUtils.getNow()){
		DateTime dt = DateTimeUtils.getLastDayOfMonth(
				DateTimeUtils.get(getPreQuarterYear(now),getPreQuarterEndMonth(now))
				)

		return dt
	}
	//得到本季度的开始日期
	static DateTime getStartDateOfQuarter(DateTime now=DateTimeUtils.getNow()){
		DateTime dt = DateTimeUtils.getFirstDayOfMonth(
				DateTimeUtils.get(now.year().get(),getQuarterStartMonth(now))
				)

		return dt
	}

	//得到本季度的结束日期
	static DateTime getEndDateOfQuarter(DateTime now=DateTimeUtils.getNow()){
		DateTime dt = DateTimeUtils.getLastDayOfMonth(
				DateTimeUtils.get(now.year().get(),getQuarterEndMonth(now))
				)

		return dt
	}

	//是否在明天之前
	static boolean isBeforeTomorrow(Date date){
		return isBeforeTomorrow(new DateTime(date))
	}
	static boolean isBeforeTomorrow(DateTime date){
		DateTime tommorow = new DateTime(new Date()).plusDays(1).toDateMidnight().toDateTime()

		return date<tommorow
	}

	//是否在今天之前
	static boolean isBeforeToday(Date date){
		return isBeforeToday(new DateTime(date))
	}
	static boolean isBeforeToday(DateTime date){
		DateTime today = new DateTime(new Date()).toDateMidnight().toDateTime()

		return date<today
	}

	//开始时间是否在结束时间之前
	static boolean isFromdateBeforeTodate(DateTime fromDate, DateTime toDate){
		DateTime d1 = fromDate.toDateMidnight().toDateTime()
		DateTime d2 = toDate.toDateMidnight().toDateTime()

		return d1<d2
	}

	//开始时间是否在结束时间之前(包括与结束时间相同)
	static boolean isFromdateBeforeEQTodate(DateTime fromDate, DateTime toDate){
		DateTime d1 = fromDate.toDateMidnight().toDateTime()
		DateTime d2 = toDate.toDateMidnight().toDateTime()

		return d1<=d2
	}

	/**
	* 得到本月的第一天
	* @return
	*/
   public static Date getMonthFirstDay() {
	   Calendar calendar = Calendar.getInstance();
	   calendar.set(Calendar.DAY_OF_MONTH, calendar
			   .getActualMinimum(Calendar.DAY_OF_MONTH));

	   return calendar.getTime();
   }

   public static Date getMonthFirstDay(Date date) {
	   Calendar calendar = Calendar.getInstance();
	   calendar.setTime(date)
	   calendar.set(Calendar.DAY_OF_MONTH, calendar
			   .getActualMinimum(Calendar.DAY_OF_MONTH));
	   return calendar.getTime()
   }

   /**
	* 得到本月的最后一天
	*
	* @return
	*/
   public static Date getMonthLastDay() {
	   Calendar calendar = Calendar.getInstance();
	   calendar.set(Calendar.DAY_OF_MONTH, calendar
			   .getActualMaximum(Calendar.DAY_OF_MONTH));
	   return calendar.getTime()
   }

  public static Date getMonthLastDay(Date date) {
	  Calendar calendar = Calendar.getInstance();
	  calendar.setTime(date)
	  calendar.set(Calendar.DAY_OF_MONTH, calendar
			  .getActualMaximum(Calendar.DAY_OF_MONTH));
	  return calendar.getTime()
  }

   /**
    * 得到某月的总天数
    * @return
    */
   public static int getMonthTotalDay(Date date){
	   Calendar calendar = Calendar.getInstance();
	   calendar.setTime(date)
	   return calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
   }

   /**
    * 获取两个日期的差
    * @param formDate
    * @param endDate
    * @return
    */
   public static long getQuot(Date formDate, Date endDate){
	   long quot = 0;
	   quot = formDate.getTime() - endDate.getTime();
	   return quot / 1000 / 60 / 60 / 24;
   }
   /**
   * 获取两个时间的时间差（h）
   * @param formDate
   * @param endDate
   * @return
   */
   public static double getQuotTime(Date formDate, Date endDate){
	   long quot = 0;
	   quot = (endDate.getTime() - formDate.getTime());
	   Integer i = new Integer('3600000')
	   BigDecimal b = new BigDecimal(quot/i);
	   Integer c = new Integer('2')
	   return b.setScale(c, BigDecimal.ROUND_HALF_UP).doubleValue()
   }
   /**
    * 获取两个日期的月份差
    * @param fromDate
    * @param endDate
    * @return
    */
   public static long getMonthDiff(Date fromDate, Date endDate){
	   long quot = 0;

	   DateTime dt1 = DateTimeUtils.toDateTime(fromDate)
	   DateTime dt2 = DateTimeUtils.toDateTime(endDate)
	   long year1 = dt1.year().get()
	   long month1 = dt1.monthOfYear().get()

	   long year2 = dt2.year().get()
	   long month2 = dt2.monthOfYear().get()

	   quot = (year2 - year1) * 12 + (month2 - month1);

	   return quot;
	  }

   //============================================================
   //判断时期是否是星期几
   // dateTime 日期
   // dayOfWeek 1 - 7 星期一 ～ 星期天
   // @return true OR false
   //============================================================
   public static boolean getDayOfWeekIsOrTrue(DateTime dateTime, int dayOfWeek) {
		def week = (int)dateTime.dayOfWeek().get()
		if( week == dayOfWeek){
			return true
		}else{
			return false
		}
   }

   //============================================================
   // 获取某月工作日
   // computeDateTime 日期
   // @return
   //============================================================
   /*public static int getDayOfWeekInMonth(String computeMonth){
	   Date computeDateTime = Utils.yearMonthString2Date(computeMonth)
	   Date firstDayOfMonth = getFirstDayOfMonth(computeDateTime)    // 当月第一天
	   Date lastDayOfMonth = getLastDayOfMonth(computeDateTime)    // 当月最后一天
	   return getWorkingDaysBetween(firstDayOfMonth,lastDayOfMonth)

   }

   //============================================================
   // 获取某月有星期六有多少天
   // computeDateTime 日期
   // @return
   //============================================================
   public static int getDaysInMonthBySaturday(String computeMonth){
	   Date computeDateTime = Utils.yearMonthString2Date(computeMonth)
	   Date firstDayOfMonth = getFirstDayOfMonth(computeDateTime)    // 当月第一天
	   Date lastDayOfMonth = getLastDayOfMonth(computeDateTime)    // 当月最后一天
	   return getSaturDaysBetween(firstDayOfMonth,lastDayOfMonth)
   }

   *//**
    * 得到月份的星期一共有哪几天
    * 如 2015-04有三天是星期一 即返回[6,13,27]
    * @param computeMonth
    * @return
    *//*
   public static List<Integer> getWeekInMonth(String computeMonth){
	   List<Integer> result = []
	   Date computeDateTime = Utils.yearMonthString2Date(computeMonth)

	   //得到当月总天数
	   int totalDays = getMonthTotalDay(computeDateTime)

	   //得到当月第一天;
	   Date beginDate = getMonthFirstDay(computeDateTime)

	   DateTime tempDateTime = DateTimeUtils.toDateTime(beginDate)
	   while(totalDays -- > 0){
		   def week = (int)tempDateTime.dayOfWeek().get()
		   if(week == 1){
			   result << tempDateTime.dayOfMonth().get()
		   }
		   tempDateTime = tempDateTime.plusDays(1).toDateMidnight().toDateTime()
	   }
	   return result;

   }*/
   //============================================================
   // 获取某个日期
   // date 日期
   // d 设置日期为d号
   // m 传入时间的月份数加 m
   // @return
   //============================================================
   public static Date getDateBySetTime(Date date, int d, int m){
	   SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
	   Calendar c = Calendar.getInstance();//获得一个日历的实例
	   c.setTime(date);
	   c.set(Calendar.DATE,d);
	   c.add(Calendar.MONTH, m);
	   return c.getTime();
  }

	public static Date getDateBySetTime(Date date, int hour, int min, int sec){
		SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar c = Calendar.getInstance();//获得一个日历的实例
		c.setTime(date);
		c.set(Calendar.HOUR,hour);
		c.set(Calendar.MINUTE, min);
		c.set(Calendar.SECOND, sec);
		return c.getTime();
	}

   public static Date getTheTime(Date date, int d, int m){
	   SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
	   Calendar c = Calendar.getInstance();//获得一个日历的实例
	   c.setTime(date);
	   if(d!=0){
		   c.add(Calendar.DATE, d);
	   }
	   if(m!=0){
		   c.add(Calendar.MONTH, m);
	   }
	   return c.getTime();
  }

   public static Date getTimeHM(Date date, Date hm){
	   SimpleDateFormat h = new SimpleDateFormat("HH");
	   SimpleDateFormat m = new SimpleDateFormat("mm");
	   Calendar c = Calendar.getInstance();//获得一个日历的实例
	   c.setTime(date);
	   c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(h.format(hm)));
	   c.set(Calendar.MINUTE, Integer.parseInt(m.format(hm)));
	   c.set(Calendar.SECOND,Integer.parseInt('00'))
	   return c.getTime();
  }

   public static double getTimeCoincidence(Date date, Date beginTime1, Date endTime1, Date beginTime2, Date endTime2){
	   SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
	   beginTime1=getTimeHM(date, beginTime1)
	   endTime1=getTimeHM(date, endTime1)
	   beginTime2=getTimeHM(beginTime2, beginTime2)
	   endTime2=getTimeHM(endTime2, endTime2)
	   long b1 = beginTime1.getTime();
	   long e1 = endTime1.getTime();
	   long b2 = beginTime2.getTime();
	   long e2 = endTime2.getTime();
	   double coincidenceTime=0
	   if(b1<=b2&&e1>=e2){//（b1---【b2-----e2】--e1）1包含2
		   coincidenceTime=getQuotTime(beginTime2,endTime2);
	   }else if(b1>=b2&&e1<=e2){//【b2---（b1-----e1）--e2】2包含1
		   coincidenceTime=getQuotTime(beginTime1,endTime1);
	   }else if(b1>=b2&&b1<=e2&&e2<=e1){//（b1---【b2---e1）----e2】 相交1
		   coincidenceTime=getQuotTime(beginTime1,endTime2);
	   }else if(b1<=b2&&e1<=e2&&e1>=b2){//【b2---(b1---e2】----e1) 相交2
		   coincidenceTime=getQuotTime(beginTime2,endTime1);
	   }else if(e1<=b2||b1>=e2){//（b1-----e1）【b2-----e2】或【b2-----e2】（b1-----e1）不相交
		   coincidenceTime=0;
	   }else{
		   coincidenceTime=0;
	   }
	   return coincidenceTime;
   }

   public static String toDateForLong(Long time){
	   SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	   String d = format.format(time);
	   return d;
   }

}
